﻿using System.Data.Entity.Core.Objects;

namespace Sidvall.Data.Entity
{
    public abstract class StorageManagerDbContextBase<TManager, TContext> : System.IDisposable
        where TContext : System.Data.Entity.DbContext
        where TManager : StorageManagerDbContextBase<TManager, TContext>
    {
        #region Public Members

        #region ObjectContext

        private TContext _ObjectContext;
        public TContext ObjectContext
        {
            get
            {
                return this._ObjectContext;
            }
            protected set
            {
                this._ObjectContext = value;
            }
        }

        #endregion

        #region Dispose

        public void Dispose()
        {
            Dispose(true);
            System.GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.ObjectContext != null)
                {
                    this.ObjectContext.Dispose();
                    this.ObjectContext = null;
                }
            }
        }

        #endregion

        #endregion
        #region Factory Members

        #region GetManager

        protected static TManager GetManager()
        {
            return GetManager(string.Empty, null);
        }
        protected static TManager GetManager(string nameOrConnectionString)
        {
            return GetManager(nameOrConnectionString, null);
        }
        protected static TManager GetManager(string nameOrConnectionString, System.Data.Entity.Infrastructure.DbCompiledModel model)
        {
            var dbContext = CreateContext(nameOrConnectionString, model, null);
            return GetManager(dbContext);
        }
        protected static TManager GetManager(ObjectContext context)
        {
            if (context == null)
                throw new System.ArgumentNullException("context");
            var dbContext = CreateContext(null, null, context);
            return GetManager(dbContext);
        }
        private static TManager GetManager(TContext dbContext)
        {
            var manager = (TManager)(System.Activator.CreateInstance(typeof(TManager), true));
            manager.ObjectContext = dbContext;
            return manager;
        }

        #endregion

        #endregion
        #region Private Members

        #region CreateContext

        private static TContext CreateContext(string nameOrConnectionString, System.Data.Entity.Infrastructure.DbCompiledModel model, ObjectContext context)
        {
            TContext item;

            if (model != null)
            {
                if (!string.IsNullOrEmpty(nameOrConnectionString))
                    item = (TContext)(System.Activator.CreateInstance(typeof(TContext), nameOrConnectionString, model));
                else
                    item = (TContext)(System.Activator.CreateInstance(typeof(TContext), model));
            }
            else if (context != null)
            {
                item = (TContext)(System.Activator.CreateInstance(typeof(TContext), context, true));
            }
            else if (!string.IsNullOrEmpty(nameOrConnectionString))
            {
                item = (TContext)(System.Activator.CreateInstance(typeof(TContext), nameOrConnectionString));
            }
            else
            {
                item = (TContext)(System.Activator.CreateInstance(typeof(TContext)));
            }
            item.Configuration.LazyLoadingEnabled = false;

            return item;
        }

        #endregion

        #endregion
        #region Constructors

        protected StorageManagerDbContextBase()
        {
        }

        #endregion
    }
}
